﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using ImageProcessing.Utilities;

namespace ImageProcessing.IntermediateClasses
{
    class Morphology
    {
        private Bitmap originalImage;
        private Bitmap resultedImage;
        private Bitmap resultedImageT;
        private int[,] se;
        private Noise.Index origin;
        private int maskWidth;
        private int maskHeigth;
        private Colour.ColorsStruct[,] paddedBuffer;
        private Colour.ColorsStruct[,] Buffer;

        public Bitmap OriginalImage
        {
            get
            {
                return this.originalImage;
            }
            set
            {
                this.originalImage = value;
            }
        }

        public int[,] Se
        {
            get
            {
                return this.se;
            }
            set
            {
                this.se = value;
            }
        }
        public Noise.Index Origin
        {
            get
            {
                return this.origin;
            }
            set
            {
                this.origin = value;
            }
        }
        public int MaskHeight
        {
            get
            {
                return this.maskHeigth;
            }
            set
            {
                this.maskHeigth = value;
            }
        }
        public int MaskWidth
        {
            get
            {
                return this.maskWidth;
            }
            set
            {
                this.maskWidth = value;
            }
        }

        public Morphology(Bitmap oldImage, int [,] Se)
        {
            this.originalImage = oldImage;
            this.se = Se;
            this.Buffer = new Colour.ColorsStruct[originalImage.Height, originalImage.Width];
        }

        public Colour.ColorsStruct[,] Padding(Bitmap oldImage,int newHeight, int newWidth)
        {
            try
            {
                this.paddedBuffer = new Colour.ColorsStruct[newHeight, newWidth];
                for (int i = 0; i < newWidth; i++)
			    {
                    for (int j = 0; j < this.maskHeigth / 2; j++)
                    {
                        this.paddedBuffer[j, i].Red = 0;
                        this.paddedBuffer[j, i].Green = 0;
                        this.paddedBuffer[j, i].Blue = 0;
                    }
                    for (int j = this.originalImage.Height; j < newHeight; j++)
                    {
                        this.paddedBuffer[j, i].Red = 0;
                        this.paddedBuffer[j, i].Green = 0;
                        this.paddedBuffer[j, i].Blue = 0;
                    }
                }
                for (int i = (this.maskHeigth/2); i < originalImage.Height + this.maskHeigth/2; i++)
                {
                    for (int j = this.maskWidth/2; j < this.originalImage.Width + this.maskWidth/2; j++)
                    {
                        this.paddedBuffer[i, j].Red = this.originalImage.GetPixel(j - (this.maskWidth / 2), i - (this.maskHeigth / 2)).R;
                        this.paddedBuffer[i, j].Green = this.originalImage.GetPixel(j - (this.maskWidth / 2), i - (this.maskHeigth / 2)).G;
                        this.paddedBuffer[i, j].Blue = this.originalImage.GetPixel(j - (this.maskWidth / 2), i - (this.maskHeigth / 2)).B;
                    }
                    for (int j = 0; j < this.maskWidth/2; j++)
                    {
                        this.paddedBuffer[i, j].Red = 0;
                        this.paddedBuffer[i, j].Green = 0;
                        this.paddedBuffer[i, j].Blue = 0;
                    }
                    for (int j = this.originalImage.Width+(this.maskWidth/2) +1; j < newWidth; j++)
                    {
                        this.paddedBuffer[i, j].Red = 0;
                        this.paddedBuffer[i, j].Green = 0;
                        this.paddedBuffer[i, j].Blue = 0;
                    }
                }
                return this.paddedBuffer;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        public Bitmap Dilation()
        {

            int newHeight, newWidth;
            if (this.maskHeigth % 2 == 0)
                newHeight = this.originalImage.Height + this.maskHeigth;
            else
                newHeight = this.originalImage.Height + this.maskHeigth-1;
            if (this.maskWidth % 2 == 0)
                newWidth = this.originalImage.Width + this.maskWidth;
            else
                newWidth = this.originalImage.Width + this.maskWidth - 1;

            ArithmaticLogicOperations arithmaticLogicOp = new ArithmaticLogicOperations();
            this.resultedImage = arithmaticLogicOp.ConvertToGreyScale(this.originalImage);
            this.resultedImageT = BinaryImage(this.resultedImage);
            this.Padding(this.resultedImage,newHeight,newWidth);

            int xtemp = this.maskWidth - 1;
            int[,] seTemp = new int[this.maskHeigth, this.maskWidth];
            int originX = 0, originY = 0;
            for (int i = 0; i < this.maskWidth; i++)
            {
                for (int j = 0; j < this.maskHeigth; j++)
                {
                    if (this.origin.X == i && this.origin.Y == j)
                    {
                        originX = xtemp;
                        originY = j;
                    }
                    seTemp[j, i] = this.se[j, xtemp];                    
                }
                xtemp--;
            }
            int ytemp = this.maskHeigth - 1;
            for (int i = 0; i < this.maskHeigth; i++)
            {
                for (int j = 0; j < this.maskWidth; j++)
                {
                    if (this.origin.X == j && this.origin.Y == i)
                    {
                        originX = j;
                        originY = ytemp;
                    }
                    this.se[i, j] = seTemp[ytemp, j];                   
                }
                ytemp--;
            }

            this.resultedImage = new Bitmap(this.originalImage.Width + this.maskWidth - 1, this.originalImage.Height + this.maskHeigth - 1);
            for (int i = 0; i < this.originalImage.Height + this.maskHeigth - 1; i++)
            {
                for (int j = 0; j < this.originalImage.Width + this.maskWidth - 1; j++)
                {
                    resultedImage.SetPixel(j, i, Color.FromArgb(paddedBuffer[i, j].Red, paddedBuffer[i, j].Green, paddedBuffer[i, j].Blue));
                }
            }
            int originXTemp, originYTemp;
            for (int i = 0; i < this.originalImage.Height; i++)
            {
                for (int j = 0; j < this.originalImage.Width; j++)
                {
                    for (int k = 0; k < this.maskHeigth; k++)
                    {
                        for (int l = 0; l < this.maskWidth; l++)
                        {
                            originXTemp = j + originX;
                            originYTemp = i + originY;
                            if ((this.se[k, l] == 1) && (this.paddedBuffer[i + k, j + l].Red == 255) && (this.paddedBuffer[i + k, j + l].Green == 255) && (this.paddedBuffer[i + k, j + l].Blue == 255))
                            {
                                this.resultedImage.SetPixel(originXTemp, originYTemp, Color.FromArgb(255, 255, 255));
                            }
                        }
                    }
                }
            }
            return this.resultedImage;
        }

        public Bitmap Erosion()
        {
            int newHeight, newWidth;
            if (this.maskHeigth % 2 == 0)
                newHeight = this.originalImage.Height + this.maskHeigth;
            else
                newHeight = this.originalImage.Height + this.maskHeigth - 1;
            if (this.maskWidth % 2 == 0)
                newWidth = this.originalImage.Width + this.maskWidth;
            else
                newWidth = this.originalImage.Width + this.maskWidth - 1;

            ArithmaticLogicOperations arithmaticLogicOp = new ArithmaticLogicOperations();
            this.resultedImage = arithmaticLogicOp.ConvertToGreyScale(this.originalImage);
            this.resultedImageT = BinaryImage(this.resultedImage);
            this.Padding(this.resultedImage, newHeight, newWidth);
            
            int[,] seTemp = new int[this.maskHeigth, this.maskWidth];
            int originX = 0, originY = 0;

            this.resultedImage = new Bitmap(this.originalImage.Width + this.maskWidth - 1, this.originalImage.Height + this.maskHeigth - 1);
            for (int i = 0; i < this.originalImage.Height + this.maskHeigth - 1; i++)
            {
                for (int j = 0; j < this.originalImage.Width + this.maskWidth - 1; j++)
                {
                    resultedImage.SetPixel(j, i, Color.FromArgb(paddedBuffer[i, j].Red, paddedBuffer[i, j].Green, paddedBuffer[i, j].Blue));
                }
            }
            int originXTemp = 0, originYTemp = 0;
            bool allCoincide = true;
            for (int i = 0; i < this.originalImage.Height; i++)
            {
                for (int j = 0; j < this.originalImage.Width; j++)
                {
                    for (int k = 0; k < this.maskHeigth; k++)
                    {
                        for (int l = 0; l < this.maskWidth; l++)
                        {
                            originXTemp = j + originX;
                            originYTemp = i + originY;
                            if ((this.se[k, l] == 1) && ((this.paddedBuffer[i + k, j + l].Red != 255) || (this.paddedBuffer[i + k, j + l].Green != 255) || (this.paddedBuffer[i + k, j + l].Blue != 255)))
                            {
                                allCoincide = false;
                                break;
                            }
                        }
                        if (allCoincide == false)
                            break;
                    }
                    if (allCoincide)
                    {
                        this.resultedImage.SetPixel(originXTemp, originYTemp, Color.FromArgb(255, 255, 255));
                    }
                    else
                    {
                        this.resultedImage.SetPixel(originXTemp, originYTemp, Color.FromArgb(0, 0, 0));
                    }
                    allCoincide = true;
                }
            }
            return this.resultedImage;
        }

        public Bitmap BinaryImage(Bitmap image)
        {
            for (int i = 0; i < image.Height; i++)
            {
                for (int j = 0; j < image.Width; j++)
                {
                    int temp = (int)image.GetPixel(j, i).R;
                    if (temp < 128)
                    {
                        image.SetPixel(j, i, Color.FromArgb(0, 0, 0));
                    }
                    else
                    {
                        image.SetPixel(j,i,Color.FromArgb(255,255,255));
                    }
                }
            }
            return image;
        }
    }
}
